/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Describe：实现对多个引用池的管理
* CreateTime：2020-04-05 19:50:49
* Version：1.0
* Modify Recorder：
*************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TinyToolKit
{
    public static class TReferencePool
    {
        private static readonly Dictionary<Type, ReferenceBasePool> BasePoolsDic = new Dictionary<Type, ReferenceBasePool>();

        #region Public Func
        /// <summary>
        /// 引用池的个数
        /// </summary>
        public static int Count => BasePoolsDic.Count;

        /// <summary>
        /// 获取指定的引用池正在使用的个数
        /// </summary>
        /// <typeparam name="T">引用池类型</typeparam>
        /// <returns>返回该类的引用池正在使用的个数</returns>
        public static int GetUsingReferenceCount<T>() where T : class, IReference,new()
        {
            return GetBasePool(typeof(T)).UsingReferenceCount;   
        }

        /// <summary>
        /// 获取指定的引用池还未使用的个数
        /// </summary>
        /// <typeparam name="T">引用池类型</typeparam>
        /// <returns>返回该类的引用池还未使用的个数</returns>
        public static int GetUnusedReferenceCount<T>() where T : class, IReference, new()
        {
            return GetBasePool(typeof(T)).UnusedReferenceCount; 
        }

        /// <summary>
        /// 从引用池获取引用
        /// </summary>
        /// <typeparam name="T">引用的类型</typeparam>
        /// <returns>引用</returns>
        public static T Acquire<T>() where T : class, IReference, new()
        {
            return GetBasePool(typeof(T)).Acquire<T>();
        }

        /// <summary>
        /// 从引用池获取引用
        /// </summary>
        /// <param name="refType">引用的类型</param>
        /// <returns>引用</returns>
        public static IReference Acquire(Type refType)
        {
            return GetBasePool(refType).Acquire();
        }

        /// <summary>
        /// 归还引用到引用池
        /// </summary>
        /// <param name="reference">要归还的引用</param>
        public static void Release(IReference reference)
        {
            GetBasePool(reference.GetType()).Release(reference);
        }

        /// <summary>
        /// 添加指定个数的引用到引用池
        /// </summary>
        /// <typeparam name="T">引用类型</typeparam>
        /// <param name="count">添加的数量</param>
        public static void Add<T>(int count)
        {
            GetBasePool(typeof(T)).Add(count);
        }

        /// <summary>
        /// 添加指定个数的引用到引用池
        /// </summary>
        public static void Add(Type refType,int count)
        {
            GetBasePool(refType).Add(count);
        }

        /// <summary>
        /// 从引用池里移除指定个数的引用，如果引用池中剩余数量少于指定数量，则会清空剩余的数量
        /// </summary>
        /// <typeparam name="T">引用类型</typeparam>
        /// <param name="count">移除的个数</param>
        public static void Remove<T>(int count) 
        {
            GetBasePool(typeof(T)).Remove(count);
        }

        /// <summary>
        /// 从引用池里移除指定个数的引用，如果引用池中剩余数量少于指定数量，则会清空剩余的数量
        /// </summary>
        public static void Remove(Type refType, int count)
        {
            GetBasePool(refType).Remove(count);
        }

        /// <summary>
        /// 从引用池里移除所有的引用
        /// </summary>
        public static void RemoveAll<T>()
        { 
            GetBasePool(typeof(T)).RemoveAll();
        }

        /// <summary>
        /// 从引用池里移除所有的引用
        /// </summary>
        public static void RemoveAll(Type refType)
        {
            GetBasePool(refType).RemoveAll();
        }

        /// <summary>
        /// 清除所有引用池
        /// </summary>
        public static void ClearAllPools() 
        {
            lock (BasePoolsDic)
            {
                foreach (KeyValuePair<Type, ReferenceBasePool> basePool in BasePoolsDic)
                {
                    basePool.Value.RemoveAll();
                }
                BasePoolsDic.Clear();
            }
        }
        #endregion

        #region Internal Func
        private static bool CheckReferenceType(Type refType)
        {
            if (refType == null || refType.IsClass == false || refType.IsAbstract || typeof(IReference).IsAssignableFrom(refType) == false)
                return false;
            return true;
        }

        private static ReferenceBasePool GetBasePool(Type refType)
        {
            if (CheckReferenceType(refType) == false) return null;

            ReferenceBasePool basePool;
            lock (BasePoolsDic)
            {
                if (BasePoolsDic.TryGetValue(refType,out basePool) == false)
                {
                    basePool = new ReferenceBasePool(refType);
                    BasePoolsDic.Add(refType, basePool);
                }
            }

            return basePool;
        }
        #endregion
    }
}

